﻿using System;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Windows.Forms;
using SSAT.ATSDriver;
using SSAT.Commands;
using SSAT.Utils;
using System.IO;
using System.Drawing;

namespace SSAT.Forms
{
    public partial class MainForm : Form
    {
        private SqlConnection _currentConnection;
        private TimeSpan _fetchingTime;
        private static readonly TimeSpan OneSecond = new TimeSpan(0, 0, 1);
        private XEventSessionParams _currentXEventSession;
        private Report _lastReport;

        public SqlConnection CurrentConnection
        {
            get { return _currentConnection; }
        }

        public MainForm()
        {
            InitializeComponent();
            Initialize();
            lblStatusImage.Text = string.Empty;
            SetCurrentConnection(null);
            SetupIcons();
        }

        // Due to some inknown error in VS I'm setting icons
        // through code.
        private void SetupIcons()
        {
            connectToolStripMenuItem.Image = Resources.Connect;
            closeConnectionToolStripMenuItem.Image = Resources.CloseConnection;
            saveReportToolStripMenuItem.Image = Resources.SaveReport;
            troubleshooterToolStripMenuItem.Image = Resources.Run;
            monitorToolStripMenuItem.Image = Resources.Monitor;

            tsbConnect.Image = connectToolStripMenuItem.Image;
            tsbCloseConnection.Image = closeConnectionToolStripMenuItem.Image;
            tsbSaveReport.Image = saveReportToolStripMenuItem.Image;
            tsbTroubleshooter.Image = troubleshooterToolStripMenuItem.Image;
            tsbMonitor.Image = monitorToolStripMenuItem.Image;
        }

        private void SetLastReport(Report report)
        {
            _lastReport = report;
            bool enabled = _lastReport != null && !string.IsNullOrEmpty(_lastReport.AtsReport.GetContent());
            SaveReportCommand.Enabled = enabled;
            PrintReportAgainCommand.Enabled = enabled;
        }

        private void UpdateState()
        {
            Text = Constants.ProgramName;
            string state = Resources.NotConnected;
            if (_currentConnection != null)
            {
                state = GetStateOfCurrentConnection();
                Text = string.Format(Resources.ProgramTitleWhenConnectedFormat, Constants.ProgramName, ConnectionHelper.GetServerName(_currentConnection));
                _connectionNullGroup.Unfreeze();
            }
            else
            {
                _connectionNullGroup.Freeze();
            }
            SetStateText(state);
            UpdateFetchingTimeLabel();
            SetLastReport(null);
            SetXEventNotReady();
        }

        private string GetStateOfCurrentConnection()
        {
            string state = _currentConnection.State.ToString();
            if (_connectionStates.ContainsKey(_currentConnection.State))
            {
                state = _connectionStates[_currentConnection.State];
            }
            return state;
        }

        private void SetStateText(string state)
        {
            UIHelper.InvokeSafely(this, delegate
            {
                lblState.Text = string.Format(Resources.ConnectionStateTextFormat, Resources.ConnectionState, state);
            });
        }

        private void SetXEventState(string state)
        {
            UIHelper.InvokeSafely(this, delegate
            {
                lblXEventStatus.Text = string.Format(Resources.XEventSessionState, state);
            });
        }

        private void MainForm_Shown(object sender, EventArgs e)
        {
            ShowConnectToServerDialog();
        }

        private void ShowConnectToServerDialog()
        {
            using (ConnectionForm form = new ConnectionForm(_currentConnection))
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    SetCurrentConnection(form.Connection);
                }
            }
        }

        private void CloseCurrentConnection()
        {
            if (_currentConnection != null)
            {
                CloseXEventSession();
                ConnectionHelper.CloseConnection(_currentConnection);
                _currentConnection.StateChange -= OnConnectionStateChange;
            }
            SetConnectionStatusOffLine();
            CloseConnectionCommand.Enabled = false;
        }

        private void SetConnectionStatusOffLine()
        {
            SetConnectionStatusImage(Resources.OffLine.ToBitmap());
        }

        private void SetConnectionStatusImage(Bitmap bmp)
        {
            lblStatusImage.Image = bmp;
        }

        private void CloseXEventSession()
        {
            SetXEventNotReady();
            if (_currentConnection != null && _currentConnection.State == ConnectionState.Open)
            {
                AtsDriverFacade.PostCleanup(_currentConnection, _currentXEventSession);
            }
        }

        public void SetCurrentConnection(SqlConnection connection)
        {
            CloseCurrentConnection();
            _currentConnection = connection;
            UpdateState();
            if (connection != null)
            {
                SetConnectionStatusOnLine();
                connection.StateChange += OnConnectionStateChange;
                PrepareXEventSession();
            }
        }

        private void SetConnectionStatusOnLine()
        {
            SetConnectionStatusImage(Resources.OnLine.ToBitmap());
        }

        private void PrepareXEventSession()
        {
            bwPrepareXEventSession.RunWorkerAsync();
        }

        private void OnConnectionStateChange(object sender, StateChangeEventArgs e)
        {
            switch( e.CurrentState)
            {
                case ConnectionState.Open:
                    SetConnectionStatusOnLine();
                    break;
                default:
                    SetConnectionStatusOffLine();
                    break;
            }
            UpdateState();
        }

        public void FetchAuthentificationInfo()
        {
            if (!bwFetchAuthInfo.IsBusy)
            {
                OnBeginFetching();
                bwFetchAuthInfo.RunWorkerAsync();
            }
            else
            {
                AppConsole.WriteLine(Resources.WaitUntilThisRequestEnded);
            }
        }

        private void bwFetchAuthInfo_DoWork(object sender, DoWorkEventArgs e)
        {
            if (_currentXEventSession == null)
            {
                AppConsole.WriteLine(Resources.XEventSessionNotYetReady);
            }
            UIHelper.InvokeSafely(this, DisableCommandsWhichDependOnFetchAuthInfo);
            AppConsole.WriteLine(Resources.FetchingTroubleInfo);
            e.Result = AtsDriverFacade.AuthenticationTroubleshooterRun(_currentXEventSession);
            AppConsole.WriteLine(Resources.TroubleInfoFetched);
        }

        private void DisableCommandsWhichDependOnFetchAuthInfo()
        {
            _runningAtsDriverGroup.Freeze();
        }

        private void EnableControlsWhichDependsOnFetchAuthInfo()
        {
            CloseConnectionCommand.Enabled = true;
            ConnectToServerCommand.Enabled = true;
            ReconnectCommand.Enabled = true;
        }

        private void bwFetchAuthInfo_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ReceiveReport(e);
        }

        private void PrintReport(Report report)
        {
            if (report == null)
            {
                return;
            }
            string reportContent = report.AtsReport.GetContent();
            foreach (string content in reportContent.Split(new string[] { ATSDriverResources.SeparatingLine }, StringSplitOptions.RemoveEmptyEntries))
            {
                string valueToPrint = content.Trim();
                if (!string.IsNullOrEmpty(valueToPrint))
                {
                    AppConsole.WriteSeparately(valueToPrint);
                }
            }
        }

        public void PrintLastReport()
        {
            if (_lastReport != null)
            {
                AppConsole.WriteInfo(Resources.PrintingLastReport);
                PrintReport(_lastReport);
            }
            else
            {
                AppConsole.WriteError(Resources.ThereIsNoReport);
            }
        }

        public void SaveLastReport()
        {
            if (_lastReport == null)
            {
                AppConsole.WriteError(Resources.ThereIsNoReport);
                return;
            }
            if (saveReportDialog.ShowDialog() == DialogResult.OK)
            {
                using (StreamWriter file = new StreamWriter(saveReportDialog.FileName, false))
                {
                    file.WriteLine(_lastReport.AtsReport.GetContent());
                }
                AppConsole.WriteLine(string.Format(Resources.ReportSavedToFile, saveReportDialog.FileName));
            }
        }

        private void tmrFetchingTime_Tick(object sender, EventArgs e)
        {
            _fetchingTime = _fetchingTime.Add(OneSecond);
            UpdateFetchingTimeLabel();
        }

        private void UpdateFetchingTimeLabel()
        {
            lblFetchingTime.Text = string.Format(Resources.FetchingExecutionTimeFormat, Resources.FetchingExecutionTime, _fetchingTime.ToString());
        }

        private void OnBeginFetching()
        {
            _fetchingTime = new TimeSpan();
            UpdateFetchingTimeLabel();
            tmrFetchingTime.Enabled = true;
        }

        private void OnEndFetching()
        {
            tmrFetchingTime.Enabled = false;
        }

        private void bwPrepareXEventSession_DoWork(object sender, DoWorkEventArgs e)
        {
            if (CurrentConnection == null)
            {
                AppConsole.WriteError(Resources.ThereIsNoConnection);
            }
            SetXEventState(Resources.PreparingTroubleshooter);
            e.Result = AtsDriverFacade.CreateXEventSession(CurrentConnection);
        }

        private void bwPrepareXEventSession_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            try
            {
                _currentXEventSession = null;
                if (e.Error != null)
                {
                    Logging.Handle(e.Error);
                }
                else
                {
                    _currentXEventSession = e.Result as XEventSessionParams;
                }

                if (_currentXEventSession == null)
                {
                    SetXEventNotReady();
                }
                else
                {
                    SetXEventState(Resources.XEventSessionReady);
                    AuthentificationTroubleshooterRunCommand.Enabled = true;
                    MonitorCommand.Enabled = true;
                }
            }
            finally
            {
                EnableControlsWhichDependsOnFetchAuthInfo();
            }
        }

        private void SetXEventNotReady()
        {
            SetXEventState(Resources.XEventSessionNotReady);
            UIHelper.InvokeSafely(this, delegate
                                            {
                                                AuthentificationTroubleshooterRunCommand.Enabled = false;
                                                MonitorCommand.Enabled = false;
                                            });
        }

        private void aboutProgramToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutProgramBox aboutProgramBox = new AboutProgramBox();
            aboutProgramBox.ShowDialog();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(!bwRunMonitor.IsBusy && !bwFetchAuthInfo.IsBusy)
            {
                AppConsole.WriteLine(Resources.ExitingApplication);
                CloseCurrentConnection();   
            }
            else
            {
                e.Cancel = true;
                MessageBox.Show(Resources.WaitWhileThisOperationNotEnded, CommandsResources.Information, MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        public void RunMonitor()
        {
            DisableCommandsWhichDependOnFetchAuthInfo();
            OnBeginFetching();
            bwRunMonitor.RunWorkerAsync();
        }

        private void bwRunMonitor_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = AtsDriverFacade.MonitorRun(_currentConnection, _currentXEventSession);
        }

        private void bwRunMonitor_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            ReceiveReport(e);
        }

        private void ReceiveReport(RunWorkerCompletedEventArgs e)
        {
            Report report = null;
            try
            {
                if (e.Error != null)
                {
                    Logging.Handle(e.Error);
                }
                else
                {
                    report = e.Result as Report;
                    PrintReport(report);
                    DisableCommandsWhichDependOnFetchAuthInfo();
                }
            }
            finally
            {
                SetLastReport(report);
                OnEndFetching();
                PrepareXEventSession();
            }
        }
    }
}
